#ifndef AFCORE_COMMON_LOG_APPENDER_APPENDER_CONSOLE_COLOR_WINCOLOR_
#define AFCORE_COMMON_LOG_APPENDER_APPENDER_CONSOLE_COLOR_WINCOLOR_

#include <memory>
#include <array>

#include <windows.h>
#include <wincon.h>

#include "logcommon.h"
#include "helper.h"
#include "appender.h"
#include "nocopyable.h"

namespace afcore {

/// @brief  日志
namespace log {

/// @brief  windows 颜色记录器
/// @tparam ConsoleMutex        互斥锁
template<typename ConsoleMutex>
class CAppenderWincolor
  : public CNocopyable
  , public CAppender {
public:
  const WORD BOLD = FOREGROUND_INTENSITY;                                 ///< 粗体
  const WORD RED = FOREGROUND_RED;                                        ///< 红色
  const WORD GREEN = FOREGROUND_GREEN;                                    ///< 绿色
  const WORD CYAN = FOREGROUND_GREEN | FOREGROUND_BLUE;                   ///< 青色
  const WORD WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; ///< 白色
  const WORD YELLOW = FOREGROUND_RED | FOREGROUND_GREEN;                  ///< 黄色

  /// @brief  构造函数
  /// @param  out_handle      输出句柄
  /// @param  mode            颜色记录器颜色模式
  CAppenderWincolor(HANDLE out_handle, EAppenderColorMode mode);
  /// @brief  析构函数
  ~CAppenderWincolor() override;

  /// @brief  对应日志级别设置颜色
  /// @param  l               日志级别
  /// @param  color           颜色
  void SetColor(ELogLevel l, WORD color);
  /// @brief  记录
  /// @param  msg         日志信息
  void Log(const SLogMessage& msg) final override;
  /// @brief  刷新
  void Flush() final override;
  /// @brief  设置模式
  /// @param  pattern    模式
  void SetPattern(const std::string& pattern) final override;
  /// @brief  设置格式
  /// @param  formatter   格式
  void SetFormatter(RFormatterUptr formatter) final override;
  /// @brief  设置颜色模式
  /// @param  mode            颜色模式
  void SetColorMode(EAppenderColorMode mode);

protected:
  /// @brief  设置前景色并返回原来的颜色，以供重置使用
  /// @param  attribs     颜色
  /// @return 原来的前景色
  WORD SetForegoundColor(WORD attribs);

  /// @brief  根绝范围打印颜色
  /// @param  formatted   格式化后的数据
  /// @param  start       颜色开始位置
  /// @param  end         颜色结束位置
  void PrintRange(const RMemoryBuf& formatted, size_t start, size_t end);

  /// @brief  将数据写到文件中
  /// @param  formatted   格式化后的数据
  void WriteToFile(const RMemoryBuf& formatted);

protected:
  using RMutex = typename ConsoleMutex::RMutex;
  HANDLE out_handle_;                           ///< 输出句柄
  RMutex& mutex_;                               ///< 互斥锁
  bool in_console_ {false};                     ///< 是否用于控制台
  bool should_do_colors_ {false};               ///< 是否需要颜色
  RFormatterUptr formatter_;                    ///< 格式记录器
  std::array<WORD, kLogLevelEnable> colors_;    ///< 日志级别对应的颜色
};

template<typename ConsoleMutex>
class CAppenderWincolorStdout
  : public CAppenderWincolor<ConsoleMutex> {
public:
  explicit CAppenderWincolorStdout(EAppenderColorMode mode = EAppenderColorMode::kAppenderColorMode_Automatic);
};

template<typename ConsoleMutex>
class CAppenderWincolorStderr
  : public CAppenderWincolor<ConsoleMutex> {
public:
  explicit CAppenderWincolorStderr(EAppenderColorMode mode = EAppenderColorMode::kAppenderColorMode_Automatic);
};

using RAppenderWincolorStdout_MT = CAppenderWincolorStdout<SConsoleMutex>;
using RAppenderWincolorStdout_ST = CAppenderWincolorStdout<SConsoleNullMutex>;

using RAppenderWincolorStderr_MT = CAppenderWincolorStderr<SConsoleMutex>;
using RAppenderWincolorStderr_ST = CAppenderWincolorStderr<SConsoleNullMutex>;

} // !namespace log

} // !namespace afcore

#endif //! AFCORE_COMMON_LOG_APPENDER_APPENDER_CONSOLE_COLOR_WINCOLOR_